package com.yf.train.modules.train.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yf.base.api.exception.ServiceException;
import com.yf.base.utils.BeanMapper;
import com.yf.book.modules.book.service.UserBookService;
import com.yf.repo.enums.QuType;
import com.yf.train.enums.TrainingType;
import com.yf.repo.modules.qu.entity.Qu;
import com.yf.repo.modules.qu.service.QuService;
import com.yf.train.modules.train.dto.RepoTrainQuDTO;
import com.yf.train.modules.train.dto.ext.TrainQaDetailDTO;
import com.yf.train.modules.train.dto.ext.TrainQuDetailDTO;
import com.yf.train.modules.train.entity.RepoTrainQa;
import com.yf.train.modules.train.entity.RepoTrainQu;
import com.yf.train.modules.train.mapper.RepoTrainQuMapper;
import com.yf.train.modules.train.service.RepoTrainQaService;
import com.yf.train.modules.train.service.RepoTrainQuService;
import com.yf.train.modules.train.service.RepoTrainService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 题库训练题目业务实现类
 * </p>
 *
 * @author 聪明笨狗
 * @since 2022-03-01 18:42
 */
@Service
public class RepoTrainQuServiceImpl extends ServiceImpl<RepoTrainQuMapper, RepoTrainQu> implements RepoTrainQuService {

    @Autowired
    private RepoTrainQaService repoTrainQaService;

    @Autowired
    private QuService quService;

    @Autowired
    private UserBookService userBookService;

    @Autowired
    private RepoTrainService repoTrainService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String build(String trainId, String repoId, Integer mode, Boolean clear) {
        // 先清理
        if (clear) {

            boolean rand = false;

            if (TrainingType.RAND.equals(mode)) {
                rand = true;
            }

            String quType = null;

            if (TrainingType.QT_RADIO.equals(mode)) {
                quType = QuType.RADIO;
            }
            if (TrainingType.QT_MULTI.equals(mode)) {
                quType = QuType.MULTI;
            }
            if (TrainingType.QT_JUDGE.equals(mode)) {
                quType = QuType.JUDGE;
            }
            if (TrainingType.QT_SAQ.equals(mode)) {
                quType = QuType.SAQ;
            }
            if (TrainingType.QT_FILL.equals(mode)) {
                quType = QuType.FILL;
            }
            if (TrainingType.QT_MIX.equals(mode)) {
                quType = QuType.MIX;
            }

            // 考试错题训练
            if (TrainingType.EXAM.equals(mode)) {
                return this.buildExam(trainId, repoId);
            }

            // 构建题库训练数据
            return this.buildRepo(trainId, repoId, quType, rand);

        } else {

            QueryWrapper<RepoTrainQu> wrapper = new QueryWrapper<>();
            wrapper.lambda()
                    .eq(RepoTrainQu::getTrainId, trainId);
            wrapper.last(" LIMIT 1");
            RepoTrainQu qu = this.getOne(wrapper, false);
            if (qu == null) {
                throw new ServiceException("没有可用于训练的题目，请重新发起训练！");
            }
            return qu.getQuId();
        }
    }

    @Override
    public TrainQuDetailDTO detail(String trainId, Integer mode, String quId) {
        TrainQuDetailDTO dto = baseMapper.detail(trainId, quId);

        // 背题模式只要查看就默认正确
        if(TrainingType.REM.equals(mode) && (dto.getAnswered()==null || !dto.getAnswered())){
            RepoTrainQu qu = new RepoTrainQu();
            qu.setId(dto.getId());
            qu.setAnswered(true);
            qu.setIsRight(true);
            baseMapper.updateById(qu);

            // 同步训练状态
            repoTrainService.syncState(trainId);
        }

        return dto;
    }

    @Override
    public List<RepoTrainQuDTO> listCard(String trainId) {
        QueryWrapper<RepoTrainQu> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(RepoTrainQu::getChild, false)
                .eq(RepoTrainQu::getTrainId, trainId);

        List<RepoTrainQu> list = this.list(wrapper);

        List<RepoTrainQuDTO> dtoList = new ArrayList<>();

        if(!CollectionUtils.isEmpty(list)){
            dtoList = BeanMapper.mapList(list, RepoTrainQuDTO.class);
        }

        return dtoList;
    }

    @Override
    public RepoTrainQu getByKey(String trainId, String quId) {
        QueryWrapper<RepoTrainQu> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(RepoTrainQu::getTrainId, trainId)
                .eq(RepoTrainQu::getQuId, quId);
        wrapper.last(" LIMIT 1 FOR UPDATE");
        RepoTrainQu qu = this.getOne(wrapper, false);
        if (qu == null) {
            throw new ServiceException("题目不存在，无法训练！");
        }

        return qu;
    }

    @Override
    public void clear(String trainId) {

        QueryWrapper<RepoTrainQu> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(RepoTrainQu::getTrainId, trainId);
        this.remove(wrapper);

    }

    @Override
    public void saveAll(TrainQuDetailDTO detail) {

        // 保存题目信息
        RepoTrainQu qu = this.getByKey(detail.getTrainId(), detail.getQuId());
        if(qu == null){
            throw new ServiceException("题目不存在！");
        }
        if(qu.getAnswered()!=null && qu.getAnswered()){
            throw new ServiceException("不可以重复答题哦！");
        }

        qu.setAnswered(detail.getAnswered());
        qu.setIsRight(detail.getIsRight());
        this.updateById(qu);

        // 组合题
        if(QuType.MIX.equals(detail.getQuType())){
            List<TrainQuDetailDTO> subList = detail.getSubList();
            for(TrainQuDetailDTO sub: subList){
                this.saveAll(sub);
            }
            return;
        }

        // 保存回答信息
        List<RepoTrainQa> aList = new ArrayList<>();
        List<TrainQaDetailDTO> answerList = detail.getAnswerList();
        for(TrainQaDetailDTO item: answerList){
            RepoTrainQa qa = new RepoTrainQa();
            BeanMapper.copy(item, qa);
            aList.add(qa);
        }

        // 保存全部答案
        if(!CollectionUtils.isEmpty(aList)){
            repoTrainQaService.saveOrUpdateBatch(aList);
        }
    }


    /**
     * 考试错题训练构建
     * @param trainId
     * @param examId
     */
    private String buildExam(String trainId, String examId) {
        List<Qu> quList = userBookService.listForTrain(examId);
        return this.buildMain(trainId, quList);
    }

    /**
     * 保存题库训练类型的题目
     *
     * @param trainId
     * @param repoId
     * @param quType
     * @param rand
     */
    private String buildRepo(String trainId, String repoId, String quType, Boolean rand) {
        List<Qu> quList = quService.listForTrain(repoId, quType, rand);
        return this.buildMain(trainId, quList);
    }

    /**
     * 构建训练数据
     * @param trainId
     * @param quList
     * @return
     */
    private String buildMain(String trainId, List<Qu> quList){

        if (CollectionUtils.isEmpty(quList)) {
            throw new ServiceException("题库中可能没有题目，无法训练！");
        }

        List<RepoTrainQu> list = new ArrayList<>();
        int i = 1;
        for (Qu qu : quList) {
            RepoTrainQu tq = new RepoTrainQu();
            tq.setId(IdWorker.getIdStr());
            tq.setTrainId(trainId);
            tq.setQuId(qu.getId());
            tq.setChild(qu.getChild());
            tq.setRefId(qu.getRefId());
            tq.setSort(i);
            tq.setIsRight(false);
            tq.setAnswered(false);
            list.add(tq);
            i++;

            // 组合题
            if (QuType.MIX.equals(qu.getQuType())) {
                this.buildSub(tq.getId(), qu.getId(), trainId);
            }
        }
        this.saveBatch(list);

        // 返回第一项的题目，用于训练
        return list.get(0).getQuId();
    }

    /**
     * 构建组合题的子题目
     * @param tqId
     * @param quId
     * @param trainId
     */
    private void buildSub(String tqId, String quId, String trainId) {

        List<Qu> quList = quService.listByRef(quId);

        List<RepoTrainQu> list = new ArrayList<>();
        int i = 1;
        for (Qu qu : quList) {
            RepoTrainQu tq = new RepoTrainQu();
            tq.setTrainId(trainId);
            tq.setQuId(qu.getId());
            tq.setChild(true);
            tq.setRefId(tqId);
            tq.setSort(i);
            tq.setIsRight(false);
            tq.setAnswered(false);
            list.add(tq);
            i++;
        }
        this.saveBatch(list);
    }

}
